import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from "axios";
import config from "@/config";
import type { RequestConfig, InternalRequestConfig, RequestInterceptor, ResponseInterceptor } from "./types";

export default class Request {
    private axiosInstance: AxiosInstance;
    interceptors: {
        request: (fun?: RequestInterceptor) => void;
        response: (fun?: ResponseInterceptor) => void;
    };

    static requestBefore: RequestInterceptor = config => config;
    static requestAfter: ResponseInterceptor = response => response;

    constructor() {
        // 创建 axios 实例
        this.axiosInstance = axios.create({
            baseURL: config.baseUrl,
            timeout: 10000,
            headers: {
                "Content-Type": "application/json",
                "X-Requested-With": "XMLHttpRequest"
            },
            // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
            paramsSerializer: {
                serialize: params => {
                    return this.serializeParams(params);
                }
            }
        });

        // 请求拦截器
        this.axiosInstance.interceptors.request.use(
            (config: InternalRequestConfig) => {
                return Request.requestBefore(config);
            },
            error => {
                return Promise.reject(error);
            }
        );

        // 响应拦截器
        this.axiosInstance.interceptors.response.use(
            (response: AxiosResponse) => {
                return Request.requestAfter(response);
            },
            error => {
                // 处理响应错误
                if (error.response) {
                    // 服务器返回了错误状态码
                    return Request.requestAfter(error.response);
                }
                return Promise.reject(error);
            }
        );

        // 拦截器配置方法
        this.interceptors = {
            request: (fun?: RequestInterceptor) => {
                if (fun) {
                    Request.requestBefore = fun;
                } else {
                    Request.requestBefore = request => request;
                }
            },
            response: (fun?: ResponseInterceptor) => {
                if (fun) {
                    Request.requestAfter = fun;
                } else {
                    Request.requestAfter = response => response;
                }
            }
        };
    }

    /**
     * 自定义参数序列化方法
     * 将对象转换为 URL 查询字符串，数组使用逗号分隔
     * @param params 参数对象
     * @param prefix 前缀（用于嵌套对象）
     * @returns 序列化后的查询字符串
     */
    private serializeParams(params: Record<string, any>, prefix?: string): string {
        const query: string[] = [];

        for (const key in params) {
            if (Object.prototype.hasOwnProperty.call(params, key)) {
                const value = params[key];
                const fullKey = prefix ? `${prefix}[${key}]` : key;

                if (value === null || value === undefined) {
                    // 跳过 null 和 undefined
                    continue;
                } else if (Array.isArray(value)) {
                    // 数组使用逗号分隔: ids=1,2,3
                    if (value.length > 0) {
                        query.push(`${fullKey}=${value.join(",")}`);
                    }
                } else if (typeof value === "object" && !(value instanceof Date)) {
                    // 嵌套对象递归处理
                    query.push(this.serializeParams(value, fullKey));
                } else {
                    // 普通值直接拼接
                    query.push(`${fullKey}=${encodeURIComponent(String(value))}`);
                }
            }
        }

        return query.filter(Boolean).join("&");
    }

    /**
     * 判断是否为完整 URL
     */
    static isCompleteURL(url: string): boolean {
        return /(http|https):\/\/([\w.]+\/?)\S*/.test(url);
    }

    /**
     * 处理参数中的数组，转换为逗号分隔的字符串
     * 注意：不再需要手动转换，由 paramsSerializer 处理
     */
    private processParams(params?: Record<string, any>): Record<string, any> | undefined {
        if (!params || typeof params !== "object") {
            return params;
        }

        // 直接返回原参数，让 paramsSerializer 处理数组格式
        // paramsSerializer 会自动将数组转换为逗号分隔的字符串
        return params;
    }

    /**
     * 通用请求方法
     */
    request<T = any>(options: RequestConfig = {}): Promise<T> {
        const axiosConfig: AxiosRequestConfig = {
            url: options.url,
            method: options.method || "GET",
            headers: options.headers,
            data: options.data,
            params: this.processParams(options.params), // 处理参数
            timeout: options.timeout
        };

        // 如果是完整 URL，覆盖 baseURL
        if (options.url && Request.isCompleteURL(options.url)) {
            axiosConfig.baseURL = "";
        }

        // 传递自定义配置
        const config = {
            ...axiosConfig,
            loading: options.loading,
            apiName: options.apiName,
            is: options.is
        } as InternalRequestConfig;

        return this.axiosInstance.request(config);
    }

    /**
     * GET 请求
     */
    get<T = any>(params?: any, options: RequestConfig = {}): Promise<T> {
        return this.request<T>({
            ...options,
            method: "GET",
            params
        });
    }

    /**
     * POST 请求
     */
    post<T = any>(data?: any, options: RequestConfig = {}): Promise<T> {
        return this.request<T>({
            ...options,
            method: "POST",
            data
        });
    }

    /**
     * PUT 请求
     */
    put<T = any>(data?: any, options: RequestConfig = {}): Promise<T> {
        return this.request<T>({
            ...options,
            method: "PUT",
            data
        });
    }

    /**
     * DELETE 请求
     */
    delete<T = any>(params?: any, options: RequestConfig = {}): Promise<T> {
        return this.request<T>({
            ...options,
            method: "DELETE",
            params
        });
    }

    /**
     * PATCH 请求
     */
    patch<T = any>(url: string, data?: any, options: RequestConfig = {}): Promise<T> {
        return this.request<T>({
            ...options,
            url,
            method: "PATCH",
            data
        });
    }
}
